/*
 * 1_smp.c
 * CPU0通过SGI通知其他CPU执行指定函数
 */

/* C头文件，支持标准C库, 可以跨平台 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include <tests_lib.h>
#include <io.h>

/*
 * 本测例引用了SMP消息通信机制, <smp.h>中定义了SMP相关的接口,
 */
#include <smp.h>

typedef struct {
    float op1;
    float op2;
    float result;
} calc_t;

static void multiply(void *arg)
{
    calc_t *mul = (calc_t *)arg;

    INFO("CPU[%d]: doing multiplication \n", get_cpuid());

    mul->result = mul->op1 * mul->op2;
}

static void divide(void *arg)
{
    calc_t *div = (calc_t *)arg;

    INFO("CPU[%d]: doing division \n", get_cpuid());

    div->result = div->op1 / div->op2;
}

static int smp_basic_run(void)
{
    float expect;

    /*
     * 让CPU1跑个乘法，smp_call_function()最后一个参数表示不等待执行完成
     * 检查执行结果，这里ASSERT_EQ()显然会报错
     */
    calc_t mul = {3.1415926, 3.0, 0};
    expect = mul.op1 * mul.op2;
    smp_call_function(1, multiply, (void *)&mul, false);
    ASSERT_EQ(mul.result, expect);

    /*
     * 让CPU2跑个除法且等待执行
     */
    calc_t div = {888.888, 3.14, 0};
    expect = div.op1 / div.op2;
    smp_call_function(2, divide, (void *)&div, true);
    ASSERT_EQ(div.result, expect);

    return 0;
}

DECLARE_TEST_CASE(          /* 声明了一个单元测例, 测试框架会依次调用下面的init(), run(), exit()函数 */
        smp_basic,          /* 测例名字，不用带引号"" */
        NULL,               /* 测例预初始化函数，若不需要可以为NULL. 比如可以把复位和时钟初始化放这里 */
        smp_basic_run,      /* 测例执行主体函数，必须定义 */
        NULL                /* 测例退出函数，若不需要可以为NULL. 比如结束测例后需要关时钟 */
);
